import React, { PureComponent, Fragment } from 'react';
import { Card, Form, Row, Col, DatePicker, Spin, Button, Table, Icon, Tooltip as AntdTooltip, Badge, Modal, Select } from 'antd';
import { Chart, Axis, Tooltip, Geom, Label } from 'bizcharts';
import { connect } from 'dva';
import { Link } from 'dva/router';
import moment from 'moment';
import lodash from 'lodash';
// import numeral from 'numeral';
import Debounce from 'lodash-decorators/debounce';
import Bind from 'lodash-decorators/bind';
import SyntaxHighlighter, { registerLanguage } from "react-syntax-highlighter/light";
import tex from 'react-syntax-highlighter/languages/hljs/tex';
import TomorrowNightEighties from 'react-syntax-highlighter/styles/hljs/tomorrow-night-eighties';
// import Ellipsis from '../../components/Ellipsis';
import { fmtThousands, fmtTime, fmtDateTime } from '../../utils/fmt'
import { UrlHistogramArray } from '../../utils/enum'
import PageHeaderLayout from '../../layouts/PageHeaderLayout';
import UrlFilterModal from './UrlFilterModal';
// import classNames from 'classnames';
import styles from './Urls.less'

registerLanguage('tex', tex);

@connect(({ GlobalEnumModel, UrlsModel, loading }) => ({
  GlobalEnumModel,
  UrlsModel,
  pageLoading: loading.effects['UrlsModel/query'],
  queryHistogramLoading: loading.effects['UrlsModel/queryHistogram'],
  queryHistogramItemLoading: loading.effects['UrlsModel/queryHistogramItem'],
}))
@Form.create()
export default class Urls extends PureComponent {

  state = {
    screenHeight: document.documentElement.clientHeight,
    showUrl: false,
    urlStr: '',
    urlInfo: undefined,
  };

  // 数据初始化
  componentDidMount() {
    window.addEventListener('resize', this.handleHeight);
    const { dispatch } = this.props;
    dispatch({ type: 'GlobalEnumModel/allSysName' });
    dispatch({ type: 'UrlsModel/query' });
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleHeight);
  }

  // 动态设置高度
  @Bind()
  @Debounce(400)
  handleHeight = () => {
    const screenHeight = document.documentElement.clientHeight;
    this.setState({ screenHeight });
  };

  // 查询页面所有数据
  queryPageData = (e) => {
    if (e) e.preventDefault();
    const { dispatch, form: { getFieldValue } } = this.props;
    // const histogramPrefix = getFieldValue('histogramPrefix');
    const timeRange = getFieldValue('timeRange');
    dispatch({ type: 'UrlsModel/query', payload: { min: fmtDateTime(timeRange[0]), max: fmtDateTime(timeRange[1]) } });
  }

  // 查询参数发生变化 -> 刷新页面数据
  sysNameChange = (index) => {
    const { dispatch } = this.props;
    lodash.delay(() => dispatch({ type: 'UrlsModel/query', payload: { index } }), 100);
  }

  // 日期发生变化 -> 刷新页面数据
  timeRangeChange = () => {
    const { dispatch, form: { getFieldValue } } = this.props;
    const timeRange = getFieldValue('timeRange');
    lodash.delay(() => dispatch({ type: 'UrlsModel/query', payload: { min: fmtDateTime(timeRange[0]), max: fmtDateTime(timeRange[1]) } }), 500);
  }

  // 直方图类型发生变化 -> 刷新直方图数据
  histogramPrefixChange = (histogramPrefix) => {
    const { dispatch } = this.props;
    dispatch({ type: 'UrlsModel/queryHistogram', payload: { histogramPrefix } });
  }

  // 确定Url过滤
  urlFilterOk = (formValues, reset) => {
    const { dispatch } = this.props;
    dispatch({ type: 'UrlsModel/save', payload: { showUrlFilter: false } })
    lodash.delay(() => dispatch({ type: 'UrlsModel/query', payload: { urlFilterStr: formValues.urlFilterStr } }), 200);
    if (reset instanceof Function) lodash.delay(() => reset(), 200);
  }

  // 查询表单
  queryForm() {
    const { dispatch, form: { getFieldDecorator }, GlobalEnumModel: { sysNameList, currentSysName }, UrlsModel: { queryParam }, pageLoading, queryHistogramLoading } = this.props;
    const timeRangeInitialValue = [
      queryParam.min ? moment(queryParam.min) : moment().startOf('day').subtract(1, 'day'),
      queryParam.max ? moment(queryParam.max) : moment().endOf('day'),
    ];
    const disabledButton = pageLoading || queryHistogramLoading || false;
    return (
      <Form onSubmit={this.queryPageData} layout="inline">
        <Row gutter={{ md: 0, lg: 0, xl: 0 }}>
          <Form.Item label="选择系统" style={{ width: 265 }}>
            {getFieldDecorator('index', { initialValue: currentSysName })(
              <Select placeholder="所属系统" allowClear={false} onChange={this.sysNameChange}>
                {sysNameList.map(({ index, sysName }) => (<Select.Option key={index} value={index}>{sysName}</Select.Option>))}
              </Select>
            )}
          </Form.Item>
          <Form.Item label="查询日期" style={{ width: 450 }}>
            {getFieldDecorator('timeRange', { initialValue: timeRangeInitialValue })(
              <DatePicker.RangePicker
                allowClear={false}
                format="YYYY-MM-DD HH:mm:ss"
                disabledDate={current => current > moment().add(0, 'day').endOf('day')}
                ranges={{
                  '今日': [moment().startOf('day'), moment().endOf('day')],
                  '昨日': [moment().startOf('day').subtract(1, 'day'), moment().endOf('day').subtract(1, 'day')],
                  '最近7日': [moment().startOf('day').subtract(6, 'day'), moment().endOf('day')],
                  '最近30日': [moment().startOf('day').subtract(29, 'day'), moment().endOf('day')],
                }}
                showTime={{ hideDisabledOptions: true, defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')] }}
                onOk={this.timeRangeChange}
              />
            )}
          </Form.Item>
          <Form.Item className={styles.formItemButton}>
            <Button type="primary" htmlType="submit" disabled={disabledButton}>查询</Button>
            <span className={styles.spanWidth16} />
            <Button onClick={() => dispatch({ type: 'UrlsModel/save', payload: { showUrlFilter: true } })} disabled={disabledButton}>
              <Badge dot={!!queryParam.urlFilterStr && lodash.trim(queryParam.urlFilterStr) !== ""}>Url筛选</Badge>
            </Button>
            <span className={styles.spanWidth16} />
            <Link to="/analytics/urls/data/diff">监控数据对比</Link>
          </Form.Item>
        </Row>
      </Form>
    );
  }

  // 汇总数据 - 单个卡片
  getTotalCard = (title, describe, value, loading) => {
    return (
      <Card loading={loading || false} bodyStyle={{ padding: '10px 12px 4px 12px' }} className={styles.totalCard}>
        <div className={styles.totalData}>
          <div className={styles.metaWrap}>
            <span className={styles.meta}>
              <span>{title}</span>
              <span className={styles.action}>
                <AntdTooltip title={describe}><Icon type="info-circle-o" /></AntdTooltip>
              </span>
            </span>
            <div className={styles.total}>{value}</div>
          </div>
        </div>
      </Card>
    );
  }

  // 汇总数据
  getTotal() {
    const { UrlsModel: { data: { totalData = { summaryData: {} } } } } = this.props;
    if (!totalData || !totalData.summaryData) return;
    const { summaryData: { concurrentMax = 0, costMax = 0, costSum = 0, requestCount = 0 } } = totalData;
    return (
      <div style={{ textAlign: 'center' }}>
        {this.getTotalCard('请求数', '指标说明', fmtThousands(requestCount.value))}
        <span className={styles.spanWidth16} />
        {this.getTotalCard('执行总时间', '指标说明', fmtTime(costSum.value, 2))}
        <span className={styles.spanWidth16} />
        {this.getTotalCard('最大执行时间', '指标说明', fmtTime(costMax.value, 2))}
        <span className={styles.spanWidth16} />
        {this.getTotalCard('最高并发数', '指标说明', fmtThousands(concurrentMax.value))}
      </div>
    );
  }

  // 气泡图
  getPoint() {
    const { UrlsModel: { data: { totalData = {} } } } = this.props;
    // if (!totalData) return <span />;
    const data = [];
    if (totalData && totalData.chartDate && totalData.chartDate.chartList) {
      lodash.each(totalData.chartDate.chartList, item => {
        data.push({
          url: item.key,
          docCount: item.doc_count,
          sumRequestCount: item['sum@uri@requestCount'].value,
          sumCostSum: item['sum@uri@cost_sum'].value,
          maxCostMax: item['max@uri@cost_max'].value,
          maxConcurrentMax: item['max@uri@concurrentMax'].value,
          sumBotCount: item['sum@uri@botCount'].value,
          sumNotEmptyWaitMillis: item['sum@uri@notEmptyWaitMillis'].value,
          sumRdsCount: item['sum@uri@rdsCount'].value,
        });
      });
    }
    const scale = {
      'sumCostSum': { type: 'log', alias: '总时间(ms)' },
      'maxCostMax': { type: 'log', alias: '最大时间(ms)' },
      'sumRequestCount': { type: 'linear', alias: '执行次数' },
      'maxConcurrentMax': { type: 'linear', alias: '最高并发' },
      'url': { type: 'cat', alias: 'URL' },
      'sumNotEmptyWaitMillis': { type: 'linear', alias: '非空等待总时长' },
      'sumBotCount': { type: 'linear', alias: '机器人访问次数' },
    };
    if (this.point) this.point.forceFit();
    return (
      <Chart
        forceFit={true}
        onGetG2Instance={chart => { this.point = chart }}
        height={300}
        width={1000}
        padding={[60, 'auto', 'auto', 'auto']}
        data={data}
        scale={scale}
        onPointClick={e => this.setState({ showUrl: true, urlStr: e.data._origin.url, urlInfo: e.data._origin })}
      >
        <Tooltip showTitle={false} />
        <Axis name="sumCostSum" title={{ position: "end" }} />
        <Axis name="maxCostMax" title={{ offset: 55, position: "end" }} />
        <Geom
          type="point"
          position="sumCostSum*maxCostMax"
          opacity={0.65}
          shape="circle"
          tooltip="sumCostSum*maxCostMax*sumRequestCount*maxConcurrentMax*sumNotEmptyWaitMillis*sumBotCount"
          size={["sumRequestCount", [4, 20]]}
          color={['maxCostMax', ['#008800', '#227700', '#88AA00', '#BBBB00', '#DDAA00', '#EE7700', '#FF5511', '#FF0000']]}
        />
      </Chart>
    );
  }

  // 直方图
  getHistogram() {
    const { dispatch, queryHistogramLoading, UrlsModel: { data: { histogram = { xaxisTitle: 'x', yaxisTitle: 'y' } }, queryParam: { histogramPrefix } } } = this.props;
    // if (!histogram) return <span />;
    // 直方图数据
    const data = [];
    if (histogram && histogram.titles) {
      lodash.each(histogram.titles, (title, index) => {
        data.push({ x: title, y: histogram.histogramData[index], item: `${histogramPrefix}_${(index + 1) === (histogram.titles.length) ? 'm' : index}` });
      });
    }
    const scale = {
      x: { type: 'cat', alias: histogram.xaxisTitle },
      y: { type: 'pow', alias: histogram.yaxisTitle },
    };
    if (this.chart) this.chart.forceFit();
    return (
      <Spin delay={100} spinning={queryHistogramLoading || false}>
        <Chart
          forceFit={true}
          onGetG2Instance={chart => { this.chart = chart }}
          height={300}
          width={1000}
          padding={['auto', 60, 'auto', 'auto']}
          data={data}
          scale={scale}
          onIntervalClick={e => {
            dispatch({ type: 'UrlsModel/save', payload: { showHistogramItemData: true, selectHistogramItem: e.data._origin } });
            lodash.delay(() => dispatch({ type: 'UrlsModel/queryHistogramItem', payload: { item: e.data._origin.item } }), 200);
          }}
        >
          <Axis name="x" title={{ position: "end" }} />
          <Axis name="y" title={{ offset: 70, position: "end" }} />
          <Tooltip crosshairs={{ type: "rect" }} showTitle={false} />
          <Geom type="interval" position="x*y" tooltip="x*y">
            <Label content="y" />
          </Geom>
        </Chart>
      </Spin>
    );
  }

  getCharts() {
    const { UrlsModel: { queryParam: { histogramPrefix } } } = this.props;
    return (
      <Row gutter={{ md: 8, lg: 16, xl: 16 }}>
        <Col span={2} style={{ height: 300, textAlign: 'right' }}>
          <div style={{ display: 'inline-block', textAlign: 'left', width: 80, paddingTop: 80 }}>
            {UrlHistogramArray.map(item => {
              const selected = histogramPrefix === item.value;
              return (
                <div
                  key={item.value}
                  style={{ marginTop: 6, cursor: selected ? undefined : 'pointer', color: selected ? '#1890ff' : 'rgba(0, 0, 0, 0.6)' }}
                  onClick={selected ? undefined : () => this.histogramPrefixChange(item.value)}
                >
                  <Badge key={item.value} status={selected ? 'processing' : 'default'} />
                  {item.label}
                </div>
              );
            })}
          </div>
        </Col>
        <Col span={10}>
          {this.getHistogram()}
        </Col>
        <Col span={10}>
          {this.getPoint()}
        </Col>
      </Row>
    );
  }

  // 数据表格
  getTable() {
    let { screenHeight } = this.state;
    screenHeight -= 802;
    if (screenHeight < 260) screenHeight = 500;
    const { pageLoading, UrlsModel: { data: { tableData } } } = this.props;
    let data = [];
    if (tableData
      && tableData.aggregations
      && tableData.aggregations['group_by@uri@uri']
      && tableData.aggregations['group_by@uri@uri'].buckets) {
      data = tableData.aggregations['group_by@uri@uri'].buckets;
    }

    const columns = [
      { title: '请求url', dataIndex: 'key', width: 700 },
      { title: '请求数', dataIndex: 'sum@uri@requestCount.value', width: 80, render: text => fmtThousands(text) },
      { title: '执行总时间', dataIndex: 'sum@uri@cost_sum.value', width: 100, render: text => fmtTime(text, 2) },
      { title: '最大执行时间', dataIndex: 'max@uri@cost_max.value', width: 120, render: text => fmtTime(text, 2) },
      { title: '最高并发', dataIndex: 'max@uri@concurrentMax.value', width: 80, render: text => fmtThousands(text) },
    ];
    return (
      <Table
        size="middle"
        bordered={true}
        rowKey={record => record.key}
        columns={columns}
        loading={pageLoading}
        dataSource={data}
        scroll={{ x: true, y: screenHeight }}
        pagination={{
          pageSize: 50,
          hideOnSinglePage: false,
          pageSizeOptions: ['30', '50', '100'],
          showSizeChanger: true, showQuickJumper: true,
          showTotal: total => `总记录数${total}条`,
        }}
      />
    );
  }

  // 直方图某一项数据
  getHistogramItemTable() {
    const { dispatch, queryHistogramItemLoading, UrlsModel: { showHistogramItemData, histogramItemData, selectHistogramItem } } = this.props;
    if (!histogramItemData || !histogramItemData['group_by@uri@uri'] || !histogramItemData['group_by@uri@uri'].buckets) return '';
    const buckets = histogramItemData['group_by@uri@uri'].buckets;
    let { screenHeight } = this.state;
    screenHeight -= 380;
    if (screenHeight < 200) screenHeight = 350;
    const columns = [
      { title: '请求url', dataIndex: 'key', width: 450 },
      { title: '请求数', dataIndex: 'sum@uri@requestCount.value', width: 80, render: text => fmtThousands(text) },
      { title: '执行总时间', dataIndex: 'sum@uri@cost_sum.value', width: 100, render: text => fmtTime(text, 2) },
      { title: '最大执行时间', dataIndex: 'max@uri@cost_max.value', width: 120, render: text => fmtTime(text, 2) },
      {
        title: '直方图分布', dataIndex: 'doc_count', width: 200,
        render: (_, record) => {
          const array = [];
          array.push(record['sum@uri@cost_0'].value);
          array.push(record['sum@uri@cost_1'].value);
          array.push(record['sum@uri@cost_2'].value);
          array.push(record['sum@uri@cost_3'].value);
          array.push(record['sum@uri@cost_4'].value);
          array.push(record['sum@uri@cost_5'].value);
          array.push(record['sum@uri@cost_6'].value);
          array.push(record['sum@uri@cost_m'].value);
          return `[${array.join(', ')}]`;
        },
      },
      { title: '最高并发', dataIndex: 'max@uri@concurrentMax.value', width: 80, render: text => fmtThousands(text) },
    ];
    return (
      <Modal
        width="60%"
        title={`直方图数据(${selectHistogramItem.x}ms)`}
        visible={showHistogramItemData}
        footer={null}
        onCancel={() => dispatch({ type: 'UrlsModel/save', payload: { showHistogramItemData: false } })}
      >
        <Table
          size="small"
          bordered={true}
          rowKey={record => record.key}
          columns={columns}
          loading={queryHistogramItemLoading}
          dataSource={buckets}
          scroll={{ x: true, y: screenHeight }}
          pagination={{
            pageSize: 50,
            hideOnSinglePage: false,
            pageSizeOptions: ['30', '50', '100'],
            showSizeChanger: true, showQuickJumper: true,
            showTotal: totalTmp => `总记录数${totalTmp}条`,
          }}
        />
      </Modal>
    );
  }


  render() {
    const { showUrl, urlStr, urlInfo } = this.state;
    const { dispatch, pageLoading, UrlsModel: { queryParam, showUrlFilter } } = this.props;
    return (
      <PageHeaderLayout>
        <Card bordered={false}>
          <Fragment>
            <div className={styles.queryForm}>
              {this.queryForm()}
            </div>
            <Spin delay={100} size="large" spinning={pageLoading} tip="加载数据...">
              {this.getTotal()}
              {this.getCharts()}
              {this.getTable()}
            </Spin>
          </Fragment>
        </Card>
        <Modal width={700} visible={showUrl} footer={null} onCancel={() => this.setState({ urlInfo: undefined, showUrl: false })}>
          <SyntaxHighlighter customStyle={{ height: 300, marginTop: 20 }} showLineNumbers language='tex' style={TomorrowNightEighties}>
            {urlInfo ?
              [
                `-- 总时间(ms):\t\t${urlInfo.sumCostSum} ms`,
                `-- 最大时间(ms):\t\t${urlInfo.maxCostMax} ms`,
                `-- 执行次数:\t\t${urlInfo.sumRequestCount} 次`,
                `-- 最高并发:\t\t${urlInfo.maxConcurrentMax}`,
                `-- 非空等待总时长(ms):\t${urlInfo.sumNotEmptyWaitMillis} ms`,
                `-- 机器人访问次数:\t${urlInfo.sumBotCount}`,
                ``,
                urlInfo.url,
                `\n\n\n`,
              ].join('\n')
              :
              `\n${urlStr}\n\n\n`
            }
          </SyntaxHighlighter>
        </Modal>
        <UrlFilterModal
          visible={showUrlFilter}
          confirmLoading={false}
          onCancel={() => dispatch({ type: 'UrlsModel/save', payload: { showUrlFilter: false } })}
          onOk={this.urlFilterOk}
          urlFilterStr={queryParam.urlFilterStr}
        />
        {this.getHistogramItemTable()}
      </PageHeaderLayout>
    );
  }
}
